﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.IO;
using System.Web;

namespace JZ.Common.Web
{
    public static class WebHelper
    {
        static WebHelper()
        {
            //System.Net.ServicePointManager.Expect100Continue = false;
            ServicePointManager.UseNagleAlgorithm = true;
            ServicePointManager.Expect100Continue = false;
            ServicePointManager.CheckCertificateRevocationList = true;
            ServicePointManager.DefaultConnectionLimit = ServicePointManager.DefaultPersistentConnectionLimit;
        }

        #region GetResponeStringFromUrlByPost
        public static string GetResponeStringFromUrlByPost(string requestUrl, List<RequestParameter> inParams)
        {
            return GetResponeStringFromUrlByPost(requestUrl, null, null, inParams);
        }

        public static string GetResponeStringFromUrlByPost(string requestUrl, CookieContainer cookies, NetworkCredential credential, List<RequestParameter> inParams)
        {
            return GetResponeStringFromUrlByPost(requestUrl, cookies, credential, "application/x-www-form-urlencoded", inParams);
        }

        public static string GetResponeStringFromUrlByPost(string requestUrl, CookieContainer cookies, NetworkCredential credential, string contentType, List<RequestParameter> inParams)
        {
            string requestData = RequestParameter.BuildRequestBody(inParams);

            UriBuilder uri = new UriBuilder(requestUrl);
            uri.Query = requestData;

            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri.Uri);
            request.UserAgent = "Mozilla/5.0 (compatible; MSIE 10.6; Windows NT 6.1; Trident/5.0; InfoPath.2; SLCC1; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; .NET CLR 2.0.50727) 3gpp-gba UNTRUSTED/1.0";

            if (string.IsNullOrEmpty(contentType))
            {
                request.ContentType = "application/x-www-form-urlencoded";
            }
            else
            {
                request.ContentType = contentType;
            }
            request.Method = "POST";
            request.KeepAlive = false;

            if (credential != null)
            {
                request.Credentials = credential;
            }
            else
            {
                request.Credentials = CredentialCache.DefaultCredentials;
            }

            if (cookies != null)
            {
                request.CookieContainer = cookies;
            }

            using (StreamWriter sw = new StreamWriter(request.GetRequestStream()))
            {
                try
                {
                    sw.Write(requestData);
                }
                finally
                {
                    sw.Close();
                }
            }

            HttpWebResponse response = null;
            Stream dataStream = null;
            StreamReader reader = null;

            try
            {
                response = (HttpWebResponse)request.GetResponse();

                dataStream = response.GetResponseStream();
                reader = new StreamReader(dataStream);
                string str = reader.ReadToEnd();
                return str;
            }
            catch (WebException e)
            {
                using (WebResponse errResponse = e.Response)
                {
                    HttpWebResponse httpResponse = (HttpWebResponse)e.Response;
                    using (Stream errData = errResponse.GetResponseStream())
                    {
                        string log = new StreamReader(errData).ReadToEnd();
                        WebRequestException ex = new WebRequestException(requestUrl, log, httpResponse.StatusCode.ToString());
                        throw ex;
                    }
                }
            }
            catch (Exception ex)
            {
                string msg = ex.Message;
                throw ex;
            }
            finally
            {
                if (reader != null)
                {
                    reader.Close();
                }

                if (dataStream != null)
                {
                    dataStream.Close();
                }

                if (response != null)
                {
                    response.Close();
                }
            }
        }
        #endregion

        #region GetResponeStringFromUrl
        public static string GetResponeStringFromUrl(string requestUrl, params string[] inParams)
        {
            return GetResponeStringFromUrl(requestUrl, null, null, "application/x-www-form-urlencoded", inParams);
        }

        private static string GetResponeStringFromUrl(string requestUrl, CookieContainer cookies, NetworkCredential credential, string contentType, params string[] inParams)
        {
            string requestString = requestUrl;
            if (inParams != null)
            {
                for (int i = 0; i < inParams.Length; i++)
                {
                    inParams[i] = HttpUtility.UrlEncode(inParams[i]);
                }
                requestString = string.Format(requestUrl, inParams);
            }

            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(requestUrl);
            request.UserAgent = "Mozilla/5.0 (compatible; MSIE 10.6; Windows NT 6.1; Trident/5.0; InfoPath.2; SLCC1; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; .NET CLR 2.0.50727) 3gpp-gba UNTRUSTED/1.0";
            request.Method = "GET";
            request.ContentType = contentType;
            request.KeepAlive = false;

            if (credential != null)
            {
                request.Credentials = credential;
            }
            else
            {
                request.Credentials = CredentialCache.DefaultCredentials;
            }

            if (cookies != null)
            {
                request.CookieContainer = cookies;
            }

            HttpWebResponse response = null;
            Stream dataStream = null;
            StreamReader reader = null;

            try
            {
                response = (HttpWebResponse)request.GetResponse();

                dataStream = response.GetResponseStream();
                reader = new StreamReader(dataStream);
                string str = reader.ReadToEnd();
                return str;
            }
            catch (WebException e)
            {
                using (WebResponse errResponse = e.Response)
                {
                    HttpWebResponse httpResponse = (HttpWebResponse)e.Response;
                    using (Stream errData = errResponse.GetResponseStream())
                    {
                        string log = new StreamReader(errData).ReadToEnd();
                        WebRequestException ex = new WebRequestException(requestUrl, log, httpResponse.StatusCode.ToString());
                        throw ex;
                    }
                }
            }
            catch (Exception ex)
            {
                string msg = ex.Message;
                throw ex;
            }
            finally
            {
                if (reader != null)
                {
                    reader.Close();
                }

                if (dataStream != null)
                {
                    dataStream.Close();
                }

                if (response != null)
                {
                    response.Close();
                }
            }
        }
        #endregion

        #region GetJsonResultFromUrl
        public static T GetJsonResultFromUrl<T>(string requestUrl)
        {
            string respone = GetResponeStringFromUrl(requestUrl);
            Console.WriteLine(respone);
            return JsonSerializer.Deserializer<T>(respone);
        }

        public static T GetJsonResultFromUrl<T>(string requestUrl, List<RequestParameter> inParams, bool isPost = true)
        {
            string respone = string.Empty;
            if (isPost)
            {
                respone = GetResponeStringFromUrlByPost(requestUrl, null, null, null, inParams);
                return JsonSerializer.Deserializer<T>(respone);
            }
            else
            {
                string url = BuildUrl(requestUrl, inParams);
                return GetJsonResultFromUrl<T>(url);
            }
        }
        #endregion

        #region UploadingFile
        public static T UploadingFile<T>(string requestUrl, List<RequestParameter> inParams, RequestParameter file)
        {
            HttpWebRequest http = WebRequest.Create(requestUrl) as HttpWebRequest;

            string boundary = GetBoundary();
            http.Method = "POST";
            http.UserAgent = "Mozilla/5.0 (compatible; MSIE 10.6; Windows NT 6.1; Trident/5.0; InfoPath.2; SLCC1; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; .NET CLR 2.0.50727) 3gpp-gba UNTRUSTED/1.0";
            http.ContentType = string.Format("multipart/form-data; boundary={0}", boundary);
            http.AllowWriteStreamBuffering = true;
            using (Stream request = http.GetRequestStream())
            {
                try
                {
                    var raw = BuildPostData(boundary, inParams, file);
                    request.Write(raw, 0, raw.Length);
                }
                finally
                {
                    request.Close();
                }
            }

            HttpWebResponse response = null;
            Stream dataStream = null;
            StreamReader reader = null;

            try
            {
                response = (HttpWebResponse)http.GetResponse();

                dataStream = response.GetResponseStream();
                reader = new StreamReader(dataStream);
                string str = reader.ReadToEnd();
                return JsonSerializer.Deserializer<T>(str);
            }
            catch (WebException e)
            {
                using (WebResponse errResponse = e.Response)
                {
                    HttpWebResponse httpResponse = (HttpWebResponse)e.Response;
                    using (Stream errData = errResponse.GetResponseStream())
                    {
                        string log = new StreamReader(errData).ReadToEnd();
                        WebRequestException ex = new WebRequestException(requestUrl, log, httpResponse.StatusCode.ToString());
                        throw ex;
                    }
                }
            }
            catch (Exception ex)
            {
                string msg = ex.Message;
                throw ex;
            }
            finally
            {
                if (reader != null)
                {
                    reader.Close();
                }

                if (dataStream != null)
                {
                    dataStream.Close();
                }

                if (response != null)
                {
                    response.Close();
                }
            }
        }
        #endregion

        #region Build parameters
        private static string BuildUrl(string requestUrl, List<RequestParameter> inParams)
        {
            StringBuilder sb = new StringBuilder(requestUrl);

            if (requestUrl.Contains("?"))
            {
                sb.Append("&");
            }
            else
            {
                sb.Append("?");
            }

            foreach (var param in inParams)
            {
                sb.Append(HttpUtility.UrlEncode(param.Key));
                sb.Append("=");
                sb.Append(HttpUtility.UrlEncode(param.Value));
                sb.Append("&");
            }

            string url = sb.ToString();
            url = url.Substring(0, url.Length - 1);
            return url;
        }

        private static string GetBoundary()
        {
            return HttpUtility.UrlEncode(Convert.ToBase64String(Guid.NewGuid().ToByteArray()));
        }

        private static byte[] BuildPostData(string boundary, List<RequestParameter> parameters, RequestParameter fileParameter)
        {
            string division = GetBoundary();
            string header = string.Format("--{0}", boundary);
            string footer = string.Format("--{0}--", boundary);
            string encoding = "iso-8859-1";

            StringBuilder contentBuilder = new StringBuilder();

            // add normal paramter
            foreach (RequestParameter p in parameters)
            {
                contentBuilder.AppendLine(header);
                contentBuilder.AppendLine(string.Format("content-disposition: form-data; name=\"{0}\"", p.Key));
                contentBuilder.AppendLine();
                contentBuilder.AppendLine(HttpUtility.UrlEncode(p.Value == null ? string.Empty : p.Value).Replace("+", "%20"));
            }

            // add file parameter
            byte[] bytes = null;
            using (FileStream fs = File.OpenRead(fileParameter.Value))
            {
                try
                {
                    bytes = new byte[fs.Length];
                    fs.Read(bytes, 0, Convert.ToInt32(fs.Length));
                }
                catch
                {
                    fs.Close();
                }
            }

            contentBuilder.AppendLine(header);
            contentBuilder.AppendLine(string.Format("content-disposition: form-data; name=\"{0}\"; filename=\"{1}\"", fileParameter.Key, string.Format("upload{0}", BitConverter.ToInt64(Guid.NewGuid().ToByteArray(), 0))));
            contentBuilder.AppendLine("Content-Type: image/unknown");
            contentBuilder.AppendLine("Content-Transfer-Encoding: binary");
            contentBuilder.AppendLine();
            contentBuilder.AppendLine(Encoding.GetEncoding(encoding).GetString(bytes));

            contentBuilder.Append(footer);
            return Encoding.GetEncoding(encoding).GetBytes(contentBuilder.ToString());
        }
        #endregion
    }
}
